/**
 * ---------------------------
 * Time: 2017/5/12 19:29.
 * Author: Cangshi
 * View: http://palerock.cn
 * ---------------------------
 */

'use strict';
var Cielar = {
    /**
     * 生成一个类
     * @param config
     * {
     *  thisClass: [@type = function] 包含欲生成类的基础属性赋值
     *  defaultPrototype: [@type = {object}] 默认的原型链对象
     * }
     * @returns *
     */
    createSimpleClass: function (config) {
        if (!config) {
            return null;
        }
        var thisClass = config.thisClass;
        if (!thisClass) {
            return null;
        }
        var defaultPrototype = config.defaultPrototype;
        thisClass.prototype.constructor = thisClass;
        if (defaultPrototype) {
            for (var protoName in defaultPrototype) {
                if (defaultPrototype.hasOwnProperty(protoName)) {
                    thisClass.prototype[protoName] = defaultPrototype[protoName];
                }
            }
        }
        return thisClass;
    }
};
Cielar = {
    /**
     * 用以解析一个function
     * @param func 被解析的function
     * @constructor
     */
    SimpleFunction: Cielar.createSimpleClass({
        thisClass: function (func, config) {
            this.func = func;
            this.config = config;
            this.parserFunction();
        },
        defaultPrototype: {
            /**
             * 解析
             * @funcStr function的字符串
             * @paramsStr 包含所有参数的字符串
             * @params 由单个参数字符串组成的数组
             * @body 方法体的内容
             */
            parserFunction: function () {
                this.funcStr = this.func.toString().replace(/ /g, '').replace(/\r\n/g, '');
                this.paramsStr = this.funcStr.match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1];
                this.params = this.paramsStr.replace(/ /g, '').split(',');
                this.body = this.funcStr.match(/function\(.*\)\{(\S*)}/)[1];
            },
            /**
             * 通过@params和@body生成一个function
             * @returns {Object}
             */
            buildFunction: function () {
                var funcStr = 'function(';
                if (this.params.length > 0) {
                    for (var i = 0; i < this.params.length; i++) {
                        if (i == this.params.length - 1) {
                            funcStr = funcStr + this.params[i];
                            break;
                        }
                        funcStr = funcStr + this.params[i] + ',';
                    }
                }
                funcStr = funcStr + '){' + this.body + '}';
                return eval('(' + funcStr + ')');
            },
            /**
             * 向body中添加一行代码（需为表达式）
             * @param code
             */
            bodyAppendExpress: function (code) {
                for (var codeKey in code) {
                    if (code.hasOwnProperty(codeKey)) {
                        var codeLine = '';
                        if (typeof code[codeKey] === 'string') {
                            codeLine = 'this.' + codeKey + '=\'' + code[codeKey] + '\';';
                            this.body = codeLine + this.body;
                            continue;
                        }
                        codeLine = 'this.' + codeKey + '=' + code[codeKey] + ';';
                    }
                    this.body = codeLine + this.body;
                }
            }
        }
    }),
    /**
     * 生成一个类
     * @param config
     * {
     *  thisClass: [@type = function] 包含欲生成类的基础属性赋值
     *  defaultPrototype: [@type = {object}] 默认的原型链对象
     *  parentClass: {
     *      class: [@type = function] 被继承的父类
     *      args: [@type = array] 父类所需构造参数默认值
     *  }
     * }
     * @returns *
     */
    createClass: function (config) {
        if (!config) {
            return null;
        }
        var parentClass = config.parentClass;
        var thisClass = config.thisClass;
        if (!thisClass) {
            return null;
        }
        var defaultPrototype = config.defaultPrototype;
        if (parentClass) {
            var pClass = parentClass.class;
            var args = parentClass.args;
            var doClass = new this.SimpleFunction(thisClass);
            thisClass = eval(
                '(function(' +
                doClass.paramsStr +
                '){' +
                doClass.body +
                '})'
            );
            // 自定义new事件
            thisClass.prototype = {};
            thisClass.prototype.__proto__ = pClass.prototype;
            pClass.apply(thisClass.prototype, args);
        }
        thisClass.prototype.constructor = thisClass;
        if (defaultPrototype) {
            for (var protoName in defaultPrototype) {
                if (defaultPrototype.hasOwnProperty(protoName)) {
                    thisClass.prototype[protoName] = defaultPrototype[protoName];
                }
            }
        }
        return thisClass;
    },
    newClass: function (Class, args, defaultProto) {
        var obj = {};
        if (defaultProto) {
            obj.expand(defaultProto);
        }
        obj.__proto__ = Class.prototype;
        Class.apply(obj, args);
        return obj;
    },
    Class: {
        /**
         * 状态常量
         */
        BIRTH: 1,
        RUNNING: 0,
        DEATH: 2,
        DESTROY: 3,
        /**
         * 执行父类的方法
         * @param name 方法名
         * @param thisArgs
         */
        doSuper: function (name, thisArgs) {
            var _this = this;
            if (thisArgs && thisArgs.length != 0) {
                _this = thisArgs[0];
            }
            var parent = _this.__proto__;
            _this = parent.__proto__;
            if (!parent || !_this) {
                throw new Error('无父元素');
            }
            while (!_this[name] || typeof _this[name] != 'function') {
                parent = parent.__proto__;
                _this = parent.__proto__;
                if (!parent || !_this) {
                    throw new Error('父元素无该方法');
                }
            }
            var args = [parent];
            return _this[name].apply(this, args);
        },
        /**
         * 获取父类的属性
         * @param name
         * @returns {*}
         */
        getSuper: function (name) {
            var _this = this;
            var parentPrototype = _this.__proto__;
            if (!parentPrototype) {
                throw new Error('该类未继承任何父类');
            }
            while (parentPrototype[name] == null) {
                parentPrototype = parentPrototype.__proto__;
                if (!parentPrototype[name]) {
                    throw new Error('父类不具有' + name + '属性');
                }
            }
            return parentPrototype[name];
        },
        /**
         * 获取父级对象
         * @returns {*}
         */
        super: function () {
            return this.__proto__;
        },
        /**
         * 遍历对像
         * @param callback 传入参数为对象的键值
         */
        map: function (callback) {
            var keys = Object.keys(this);
            for (var i = 0; i < keys.length; i++) {
                callback.apply(this, [keys[i]])
            }
        },
        /**
         * 克隆一个对象，只克隆它的可枚举属性
         * @returns {{}}
         */
        cloneShallow: function () {
            var clone = {};
            this.map(function (key) {
                if (this[key] && typeof this[key] == 'object') {
                    if (this[key] instanceof Array) {
                        clone[key] = this[key].slice(0);
                        return;
                    }
                    clone[key] = this[key].cloneShallow();
                } else {
                    clone[key] = this[key]
                }
            });
            return clone;
        },
        /**
         * 扩展对象属性，并返回一个新的对象
         * @param obj
         * @param isCover 是否覆盖同名属性
         * @returns {*|{}}
         */
        extend: function (obj, isCover) {
            if (!isCover) {
                isCover = false;
            }
            var _this = this.cloneShallow();
            obj.map(function (key) {
                if (isCover) {
                    _this[key] = obj[key];
                } else {
                    if (_this[key] == null) {
                        _this[key] = obj[key];
                    }
                }
            });
            return _this;
        },
        /**
         * 扩展触发该方法的属性（不包括子属性）
         * @param obj
         * @param isCover 是否覆盖同名属性
         */
        expand: function (obj, isCover) {
            if (!isCover) {
                isCover = false;
            }
            var _this = this;
            obj.map(function (key) {
                if (isCover) {
                    _this[key] = obj[key];
                } else {
                    var keys = Object.keys(_this);
                    if (keys.indexOf(key) == -1) {
                        _this[key] = obj[key];
                    }
                }
            });
        },
        /**
         * 扩展触发该方法的属性（包括子属性）
         * @param obj
         * @param isCover 是否覆盖同名属性
         */
        expandAll: function (obj, isCover) {
            if (!isCover) {
                isCover = false;
            }
            var _this = this;
            obj.map(function (key) {
                if (obj[key] && typeof obj[key] == 'object') {
                    if (obj[key] instanceof Array) {
                        _this[key] = obj[key].slice(0);
                        return;
                    }
                    if (!_this.hasOwnProperty(key)) {
                        _this[key] = {};
                    }
                    _this[key].expandAll(obj[key]);
                } else {
                    if (isCover) {
                        _this[key] = obj[key];
                    } else {
                        if (!_this.hasOwnProperty(key)) {
                            _this[key] = obj[key];
                        }
                    }
                }
            });
        },
        listArray: function (callback) {
            if (!(this instanceof Array)) {
                throw new Error('该方法只能遍历数组对象');
            }
            for (var i = 0; i < this.length; i++) {
                callback.call(this, i);
            }
        },
        removeAimInArray: function (aim) {
            if (!(this instanceof Array)) {
                throw new Error('该方法只能遍历数组对象');
            }
            for (var i = 0; i < this.length; i++) {
                if (this[i] == aim) {
                    this.splice(i, 1);
                    i--;
                }
            }
        }
    },
    Utils: {
        uniqueNum: 1000,
        /**
         * 根据当前时间戳生产一个随机id
         * @returns {string}
         */
        buildUniqueId: function () {
            var prefix = new Date().getTime().toString();
            var suffix = this.uniqueNum.toString();
            this.uniqueNum++;
            return prefix + suffix;
        },
        buildRandomPointInRect: function (x, y, width, height) {
            return new Cielar.Point({
                x: x + Math.random() * width,
                y: y + Math.random() * height
            })
        }
    },
    /**
     * 类：平面点
     * x,y 横纵坐标
     */
    Point: Cielar.createSimpleClass({
        thisClass: function (config) {
            this.config = config;
            this.init();
        },
        defaultPrototype: {
            init: function () {
                if (!this.config) {
                    this.config = {}
                }
                this.x = this.config.x;
                this.y = this.config.y;
                delete this.config;
            },
            /**
             * 获取指定距离和角度对应的平面点
             * @param distance
             * @param deg
             */
            getOtherPointFromDistanceAndDeg: function (distance, deg) {
                var radian = Math.PI / 180 * deg;
                var point = new this.constructor();
                point.x = distance * Math.sin(radian) + this.x;
                point.y = this.y - distance * Math.cos(radian);
                return point;
            },
            /**
             * 获取当前平面点与另一个平面点之间的距离
             * @param p
             * @returns {number}
             */
            getDistanceFromAnotherPoint: function (p) {
                return Math.sqrt((this.x - p.x) * (this.x - p.x) + (this.y - p.y) * (this.y - p.y));
            },
            /**
             * 获取当前平面点与另一个平面点之间的角度
             * @param p
             * @returns {number}
             */
            getDegFromAnotherPoint: function (p) {
                var usedPoint = new this.constructor({
                    x: p.x * 1000000 - this.x * 1000000, y: p.y * 1000000 - this.y * 1000000
                });
                var radian = Math.atan2(usedPoint.x * 1000000, usedPoint.y * 1000000);
                var deg = radian * 180 / Math.PI;
                return 180 - deg;
            },
            /**
             * 判断该点是否位于一矩形内部
             * @param x 矩形开始坐标x
             * @param y 矩形开始坐标y
             * @param width 矩形宽
             * @param height 矩形长
             * @returns {boolean}
             */
            isInRect: function (x, y, width, height) {
                var px = this.x;
                var py = this.y;
                if (px < x || px > x + width) {
                    return false;
                }
                return !(py < y || py > y + height);
            }
        }
    }),
    ListenerManage: Cielar.createSimpleClass({
        thisClass: function (ele) {
            this.element = ele;
            this.element.listenerManage = this;
            this.listenerMap = {}
        },
        defaultPrototype: {
            addListener: function (events, callback) {
                var eventList = events.split(' ');
                var eventMap = {};
                for (var i = 0; i < eventList.length; i++) {
                    var event = eventList[i].replace(/ /g, '');
                    if (!event || event == '') {
                        continue;
                    }
                    var id = Cielar.Utils.buildUniqueId();
                    eventMap[event] = id;
                    this.listenerMap[id] = callback;
                    this.element.addEventListener(event, this.listenerMap[id]);
                }
                return eventMap;
            },
            _removeListener: function (event, id) {
                this.element.removeEventListener(event, this.listenerMap[id]);
            },
            removeListener: function (handle) {
                var eventMap = handle;
                var _this = this;
                eventMap.map(function (key) {
                    _this._removeListener(key, eventMap[key]);
                });
            }
        }
    }),
    Color: Cielar.createSimpleClass({
        thisClass: function (config) {
            this.config = config;
            this.parseConfig();
            this.id = Cielar.Utils.buildUniqueId();
        },
        defaultPrototype: {
            parseConfig: function () {
                if (!this.config || typeof this.config != 'object') {
                    return;
                }
                switch (this.config.type) {
                    default:
                    case 'hexadecimal':
                        this.setByHexadecimal(this.config.color);
                        break;
                    case 'rgba':
                        this.setRGBA(this.config.r, this.config.g, this.config.b, this.config.a);
                        break;
                    case 'random':
                        this.setRandom();
                        break;
                }
                this.checkCompleted();
            },
            setRGBA: function (r, g, b, a) {
                this.r = r;
                this.g = g;
                this.b = b;
                this.a = a != null ? a : 1;
            },
            setRandom: function () {
                this.r = parseInt(255 * Math.random());
                this.g = parseInt(255 * Math.random());
                this.b = parseInt(255 * Math.random());
                this.a = 1;
            },
            setByHexadecimal: function (text) {
                text = text.replace(/ /g, '');
                var length = text.length;
                if (text.indexOf('#') != 0 || (length != 7 && length != 4)) {
                    throw new Error('16进制的颜色码不正确');
                }
                text = text.substring(1);
                switch (length) {
                    case 4:
                        this.setRGBA(
                            parseInt(text[0] + text[0], 16),
                            parseInt(text[1] + text[1], 16),
                            parseInt(text[2] + text[2], 16)
                        );
                        break;
                    case 7:
                        this.setRGBA(
                            parseInt(text.substring(0, 2), 16),
                            parseInt(text.substring(2, 4), 16),
                            parseInt(text.substring(4, 6), 16)
                        );
                        break;
                    default:
                        break
                }
                this.checkCompleted();
            },
            checkCompleted: function () {
                if (this.r == null || this.g == null || this.b == null) {
                    console.warn("颜色属性不完整");
                    return false;
                }
                if ((this.r < 0 || this.r > 255) || (this.g < 0 || this.g > 255) || (this.b < 0 || this.b > 255)) {
                    console.warn("颜色属性值异常");
                    return false;
                }
                return true;
            },

            checkAlpha: function () {
                if (this.a == null) {
                    this.a = 1;
                }
                if (this.a < 0 || this.a > 1) {
                    console.warn("Alpha值异常");
                    return false;
                }
                return true;
            },

            getHexColor: function () {
                if (this.checkCompleted()) {
                    var r = ("0" + this.r.toString(16)).slice(-2);
                    var g = ("0" + this.g.toString(16)).slice(-2);
                    var b = ("0" + this.b.toString(16)).slice(-2);
                    return "#" + r + g + b;
                }
                return ""
            },

            getRGBA: function () {
                if (this.checkCompleted() && this.checkAlpha()) {
                    return "rgba(" + this.r + "," + this.g + "," + this.b + "," + this.a + ")";
                }
                return ""
            },

            getRGB: function () {
                if (this.checkCompleted()) {
                    return "rgba(" + this.r + "," + this.g + "," + this.b + ")";
                }
                return ""
            }
        }
    })
};

/**
 * 为Object增加默认方法
 */
Cielar.Class.expand.call(Object.prototype, Cielar.Class);


